import spine35 from '../lib/spine-runtimes/3.5/spine-webgl.js';
import spine36 from '../lib/spine-runtimes/3.6/spine-webgl.js';
import spine37 from '../lib/spine-runtimes/3.7/spine-webgl.js';
import spine38 from '../lib/spine-runtimes/3.8/spine-webgl.js';
import spine40 from '../lib/spine-runtimes/4.0/spine-webgl.js';

const Path = require('path');
const Fs = require('fs');


export class viewUtlis {
    version = '3.8'

    canvas: any = null;
    gl: any = null;
    clearColor = [0.3, 0.3, 0.3];
    shader: any = null;
    batcher: any = null;
    mvp: any = null;
    skeletonRenderer: any = null;
    debugRenderer: any = null;
    debugShader: any = null;
    shapeRenderer: any = null;
    assetManager: any = null;
    assets: any = null;
    spine: any = null;
    imgData: any = null;
    skeletonData: any = null;
    skeleton: any = null;
    bounds: any = null;
    animationState: any = null;
    skin: any = null;
    animation: any = null;
    loop = true;
    lastFrameTime = Date.now() / 1000;
    viewScale = 1.0;
    // 拖动
    dragOffset = [0, 0];
    premultipliedAlpha = false;
    // 拖动
    isDragging = false;
    clickOffset = [0, 0];

    /**Spine运行时 */
    SpineRuntime(version = this.version) {
        this.version = version;
        let spine;
        switch (version) {
            case '3.5':
                spine = spine35;
                break;
            case '3.6':
                spine = spine36;
                break;
            case '3.7':
                spine = spine37;
                break;
            case '3.8':
                spine = spine38;
                break;
            case '4.0':
                spine = spine40;
                break;
            default:
                spine = spine38;
                break;
        }
        return spine;
    }

    /**
    * 初始化 Spine 运行
    */
    initRuntime(canvas, assets) {
        this.assets = assets;
        this.spine = this.SpineRuntime(assets.version);
        this.canvas = canvas;
        console.log('初始化 Spine 运行', this.spine, this.canvas);

        // 监听画布事件
        canvas.addEventListener('mousewheel', this.onCanvasMouseWheel.bind(this)); // 监听画布鼠标滚轮
        canvas.addEventListener('mousedown', this.onCanvasMouseDown.bind(this));   // 监听画布鼠标点击
        canvas.addEventListener('mousemove', this.onCanvasMouseMove.bind(this));   // 监听画布鼠标移动
        canvas.addEventListener('mouseup', this.onCanvasMouseUp.bind(this));       // 监听画布鼠标松开
        canvas.addEventListener('mouseleave', this.onCanvasMouseLeave.bind(this)); // 监听画布鼠标离开


        // WebGL
        if (!this.gl) {
            const config = { alpha: false };
            this.gl = canvas.getContext("webgl", config);
            if (!this.gl) {
                console.error("WebGL 不可用");
                return;
            }
            const color = this.clearColor;
            this.gl.clearColor(color[0], color[1], color[2], 1);
        }

        // Shader
        this.shader = this.spine.webgl.Shader.newTwoColoredTextured(this.gl);
        // 处理器
        this.batcher = new this.spine.webgl.PolygonBatcher(this.gl);
        // MVP 变换矩阵
        this.mvp = new this.spine.webgl.Matrix4();
        this.mvp.ortho2d(0, 0, this.canvas.width - 1, this.canvas.height - 1);
        // 骨骼渲染器
        this.skeletonRenderer = new this.spine.webgl.SkeletonRenderer(this.gl);

        // 用于调试的 debugRenderer、debugShader 和 shapeRenderer
        this.debugRenderer = new this.spine.webgl.SkeletonDebugRenderer(this.gl);
        this.debugShader = this.spine.webgl.Shader.newColored(this.gl);
        this.shapeRenderer = new this.spine.webgl.ShapeRenderer(this.gl);

        // 资源管理器
        this.assetManager = new this.spine.webgl.AssetManager(this.gl);

        this.loadAssets();
    }

    /**
    * 加载资源
    */
    loadAssets() {
        const assetManager = this.assetManager;
        if (!assetManager) {
            return;
        }
        const assets = this.assets;
        // 指定资源目录前缀
        if (assets.dir) {
            assetManager.pathPrefix = assets.dir;
        }
        // 骨骼数据
        if (assets.json) {
            // JSON
            assetManager.loadText(assets.json);
        } else if (assets.skel) {
            // skel（二进制）
            assetManager.loadBinary(assets.skel);
        } else {
            console.error('缺少骨骼数据');
            return;
        }
        // 图集和纹理
        if (assetManager.loadTextureAtlas) {
            // spine runtime 3.6+
            // loadTextureAtlas 内部会自动加载纹理
            assetManager.loadTextureAtlas(assets.atlas);
        } else {
            // spine runtime 3.5
            assetManager.loadText(assets.atlas);
            assetManager.loadTexture(assets.png);
        }
        // 是否开启纹理预乘
        if (Path.basename(assets.png).includes('pma') ||
            Path.basename(assets.atlas).includes('pma')) {
            // this.premultipliedAlpha = true;
        }

        // 等待加载
        this.loading();

    }

    initCallback: any = null;
    /**初始化完成 */
    init() {
        this.initCallback && this.initCallback();
    }

    /**
    * 等待加载
    */
    loading() {
        if (!this.assetManager) {
            return;
        }
        // 文件是否已加载完成
        if (this.assetManager.isLoadingComplete()) {
            console.log('资源加载完成');
            const result = this.loadSkeleton();
            if (!result) {
                console.error('加载骨骼数据失败');
                return;
            }

            // 设置皮肤
            if (this.skins && this.skins[0]) {
                this.setSkin(this.skins[0]);
            }

            // 播放动画
            if (this.animations && this.animations[0]) {
                this.playAnimation(this.animations[0]);
            }
            // 记录当前帧时间
            this.lastFrameTime = Date.now() / 1000;

            this.render();
            this.init();
        } else {
            // 继续等待加载
            requestAnimationFrame(this.loading.bind(this));
        }
    }

    /**
     * 加载骨骼数据
     */
    loadSkeleton() {
        const assetManager = this.assetManager,
            assets = this.assets;

        // 图集数据
        let atlas = assetManager.get(assets.atlas);
        if (this.spine.version === '3.5') {
            atlas = new this.spine.TextureAtlas(atlas);
        }

        let imgData: any = {
            list: [],
            img: assets.dir + assets.png,
            obj: {}
        };

        imgData.imgBase = this.loadImageAsBase64(assets.dir + assets.png);

        [...atlas.regions].forEach((v, __i) => {
            let obj: any = {
                name: v.name,
                width: v.width,
                height: v.height,
                offsetX: v.offsetX,
                offsetY: v.offsetY,
                rotate: v.rotate,
                x: v.x,
                y: v.y,
                degrees: v.degrees,
            }
            //设置背景精灵图样式
            obj.style = {
                width: obj.width + 'px',
                height: obj.height + 'px',
                transform: `rotate(${obj.degrees}deg)`,
                background: `url('${imgData.imgBase}') ${obj.x}px ${obj.y}px`,
                backgroundSize: `${v.originalWidth}px ${v.originalHeight}px`,
            }

            obj.styleStr = '';
            for (const key in obj.style) {
                const element = obj.style[key];
                obj.styleStr += key + ':' + element + ';';
            }

            imgData.list.push(obj);
            imgData.obj[obj.name] = obj;
        });
        this.imgData = imgData;
        // Editor.log('图集数据', this.imgData);

        // Editor.log('assets', assets);


        // 创建 AtlasAttachmentLoader 对象用于处理部位、网格、包围盒和路径
        const atlasLoader = new this.spine.AtlasAttachmentLoader(atlas);


        try {
            // 骨骼数据
            if (assets.json) {
                // 创建 skeletonJson 对象用于解析 json 文件
                const skeletonJson = new this.spine.SkeletonJson(atlasLoader);
                this.skeletonData = skeletonJson.readSkeletonData(assetManager.get(assets.json));
            } else if (assets.skel) {
                // 创建 SkeletonBinary 对象用于解析 skel 文件
                const skeletonBinary = new this.spine.SkeletonBinary(atlasLoader);
                this.skeletonData = skeletonBinary.readSkeletonData(assetManager.get(assets.skel));
            }
        } catch (error) {
            console.error(error);
            return false;
        }

        // 创建骨骼对象
        this.skeleton = new this.spine.Skeleton(this.skeletonData);

        // 计算边界
        this.bounds = this.calculateBounds();

        // 创建 AnimationState 对象用于动画控制
        const animationStateData = new this.spine.AnimationStateData(this.skeleton.data);
        this.animationState = new this.spine.AnimationState(animationStateData);

        // Done
        return true;
    }

    /**
     * 读取文件并转换为 base64 字符串
     * @param filePath 
     */
    loadImageAsBase64(filePath) {
        // 使用同步方法 readFileSync 来读取文件内容
        // 注意：在实际应用中推荐使用异步版本 readFile，避免阻塞主线程
        const imageBuffer = Fs.readFileSync(filePath);
        // 将 Buffer 转换为 base64 编码的字符串
        const base64ImageString = imageBuffer.toString('base64');
        // 返回 base64 字符串
        return `data:image/*;base64,${base64ImageString}`;
    }

    /**
     * 计算边界
     * @returns {{ offset: { x: number, y: number }, size: { x: number, y: number } }}
     */
    calculateBounds() {
        this.skeleton.setToSetupPose();
        this.skeleton.updateWorldTransform();
        const offset = new this.spine.Vector2(),
            size = new this.spine.Vector2();
        this.skeleton.getBounds(offset, size, []);
        return { offset, size };
    }

    /**
     * 皮肤列表
     */
    get skins() {
        console.log('this.skeletonData', this.skeletonData);
        if (!this.skeletonData || !this.skeletonData.skins) {
            return [];
        }
        return this.skeletonData.skins.map(v => v.name);
    }

    /**
    * 动画列表
    */
    get animations() {
        if (!this.skeletonData || !this.skeletonData.animations) {
            return [];
        }
        return this.skeletonData.animations.map(v => v.name);
    }

    /**
     * 插槽列表
     */
    get slots() {
        let list = [];
        let slots: any = [];
        try {
            for (const key in this.skeletonData.slots) {
                const element = this.skeletonData.slots[key] || {};
                let is = this.skeleton.getAttachmentByName(element.name, element.attachmentName || element.name);
                if (is) {
                    slots.push(element);
                }
            }
            // Editor.log('骨骼数据加载完成 slots', slots);
        } catch (error) {
            // Editor.log('骨骼数据加载完成 slots error', error);
        }

        list = slots.map(v => {
            let obj: any = {
                attachmentNameList: []
            };
            obj.name = v.name;
            obj.index = v.index;
            const skin = this.skeletonData.findSkin(this.skin);

            try {
                let attas = skin.getAttachments2(obj.index)
                for (var attachmentName in attas) {
                    var attachment = attas[attachmentName];
                    
                    let tempSlot=this.skeleton.slots.find((slot)=>{
                        return slot.data.name == obj.name;
                    });

                    obj.attachmentNameList.push({
                        isShow: tempSlot?.attachment?.name == attachment.attachment.name,
                        name: attachment.attachment.name,
                    });
                }
            } catch (error) {
                console.log('error', error);
            }

            return obj
        });

        return list;
    }


    /**
     * 设置皮肤
     * @param {string} skinName 皮肤名称
     */
    setSkin(name) {
        if (!this.skeleton) {
            return;
        }
        this.skin = name;
        // 设置皮肤
        this.skeleton.setSkinByName(name);
        // 重置姿势
        this.skeleton.setSlotsToSetupPose();

    }

    /**
     * 播放动画
     * @param {string} name 
     */
    playAnimation(name) {
        if (!this.skeleton) {
            return;
        }

        this.animation = name;
        // 重置姿势
        this.skeleton.setToSetupPose();
        // 播放动画
        this.animationState.setAnimation(0, name, this.loop);

    }

    /**
     * 设置插槽
     */
    setSlot(slotName,attachmentName) {
        let is = false;
        this.slots.forEach((v:any) => {
           if(v.name == slotName){
                v.attachmentNameList.forEach((item:any) => {
                    if(item.name == attachmentName && item.isShow){
                        is=true;
                    }
                });
           }
        });
       
        if(is){
            this.skeleton.setAttachment(slotName,null);
            return;
        }

        this.skeleton.setAttachment(slotName,attachmentName);
    }


    /**
    * 渲染骨骼
    */
    render() {
        if (!this.skeleton) {
            return;
        }
        // 计算帧时间差
        const now = Date.now() / 1000,
            delta = now - this.lastFrameTime;
        // 记录当前帧时间
        this.lastFrameTime = now;

        // 更新 mvp 来适配画布尺寸
        this.resizeView();

        // 清空画布
        this.gl.clear(this.gl.COLOR_BUFFER_BIT);

        // 应用动画并根据时间差值更新动画时间
        this.animationState.update(delta);
        this.animationState.apply(this.skeleton);
        // 更新骨骼 Transform
        this.skeleton.updateWorldTransform();

        // 渲染
        // 绑定 shader
        this.shader.bind();
        // 传递属性
        this.shader.setUniformi(this.spine.webgl.Shader.SAMPLER, 0);
        this.shader.setUniform4x4f(this.spine.webgl.Shader.MVP_MATRIX, this.mvp.values);
        // 渲染骨骼
        this.batcher.begin(this.shader);
        // 设置 skeletonRenderer 属性
        this.skeletonRenderer.premultipliedAlpha = this.premultipliedAlpha;
        // 渲染
        this.skeletonRenderer.draw(this.batcher, this.skeleton);
        this.batcher.end();
        // 解除 shader 绑定
        this.shader.unbind();

        // 调试
        // if (this.debug) {
        //     // 绑定 shader
        //     debugShader.bind();
        //     // 传递属性
        //     debugShader.setUniform4x4f(spine.webgl.Shader.MVP_MATRIX, mvp.values);
        //     // 设置 debugRenderer 属性
        //     debugRenderer.premultipliedAlpha = this.premultipliedAlpha;
        //     debugRenderer.drawBones = this.drawBones;
        //     debugRenderer.drawBoundingBoxes = this.drawBoundingBoxes;
        //     debugRenderer.drawRegionAttachments = this.drawBoundingBoxes;
        //     debugRenderer.drawMeshHull = this.drawMeshTriangles;
        //     debugRenderer.drawMeshTriangles = this.drawMeshTriangles;
        //     debugRenderer.drawPaths = this.drawPaths;
        //     debugRenderer.drawSkeletonXY = this.drawBones;
        //     // 开始渲染
        //     shapeRenderer.begin(debugShader);
        //     // 渲染
        //     debugRenderer.draw(shapeRenderer, skeleton);
        //     shapeRenderer.end();
        //     // 解除 shader 绑定
        //     debugShader.unbind();
        // }

        // 持续渲染
        requestAnimationFrame(this.render.bind(this));
    }

    /**
     * 更新视口尺寸
     */
    resizeView() {
        // 更新画布尺寸
        const { clientWidth, clientHeight } = this.canvas;
        if (this.canvas.width !== clientWidth || this.canvas.height !== clientHeight) {
            this.canvas.width = clientWidth;
            this.canvas.height = clientHeight;
        }
        // 骨骼位置以及缩放
        const canvasWidth = this.canvas.width,
            canvasHeight = this.canvas.height;
        // 计算中心点
        const centerX = (this.bounds.offset.x + (this.bounds.size.x / 2)) || 0,
            centerY = (this.bounds.offset.y + (this.bounds.size.y / 2)) || 0;
        // 计算缩放比例
        const ratioX = this.bounds.size.x / canvasWidth,
            ratioY = this.bounds.size.y / canvasHeight;
        let scale = Math.max(ratioX, ratioY) * 1.2;
        if (scale < 1) scale = 1;
        // 自定义缩放
        scale /= this.viewScale;
        // 最终宽高
        const width = canvasWidth * scale,
            height = canvasHeight * scale;
        // 更新矩阵
        const x = (centerX - (width / 2)) - (this.dragOffset[0] * scale),
            y = (centerY - (height / 2)) + (this.dragOffset[1] * scale);
        this.mvp.ortho2d(x, y, width, height);
        // 更新视口
        this.gl.viewport(0, 0, canvasWidth, canvasHeight);
    }


    /**
     * 画布鼠标滚轮事件回调
     * @param {WheelEvent} event 
     */
    onCanvasMouseWheel(event) {
        if (!this.assets) {
            return;
        }
        // 当前缩放
        let scale = this.viewScale;
        // 缩放步长
        const step = Math.abs(scale) >= 1 ? 0.1 : 0.05;
        // 方向
        if (event.wheelDelta > 0) {
            // 向上（放大）
            scale += step;
        } else {
            // 向下（缩小）
            scale -= step;
        }
        // 处理精度
        scale = Math.round(scale * 100) / 100;
        // 设置缩放
        this.viewScale = scale;
    }

    /**
     * 画布鼠标点击事件回调
     * @param {MouseEvent} event 
     */
    onCanvasMouseDown(event) {
        if (!this.assets) {
            return;
        }
        this.isDragging = true;
        const x = event.offsetX - this.dragOffset[0],
            y = event.offsetY - this.dragOffset[1];
        this.clickOffset = [x, y];
    }

    /**
     * 画布鼠标移动事件回调
     * @param {MouseEvent} event 
     */
    onCanvasMouseMove(event) {
        if (!this.isDragging) {
            return;
        }
        const x = event.offsetX - this.clickOffset[0],
            y = event.offsetY - this.clickOffset[1];
        this.dragOffset = [x, y];
    }

    /**
     * 画布鼠标松开事件回调
     * @param {MouseEvent} event 
     */
    onCanvasMouseUp(__event) {
        this.isDragging = false;
        this.clickOffset = [0, 0];
    }

    /**
     * 画布鼠标离开事件回调
     * @param {MouseEvent} event 
     */
    onCanvasMouseLeave(__event) {
        this.isDragging = false;
        this.clickOffset = [0, 0];
    }

}